//
//  TangramDefaultElementFactory.m
//  Tangram
//
//  Copyright (c) 2017-2018 Alibaba. All rights reserved.
//

#import "TangramDefaultElementFactory.h"
#import "TMUtils.h"
#import "TangramDefaultItemModel.h"
#import <objc/runtime.h>

@interface TangramDefaultElementFactory()

@property (nonatomic, strong) NSMutableArray<NSString *> *elementForbiddenPropertyArray;

@end


@implementation TangramDefaultElementFactory

+ (TangramDefaultElementFactory*)sharedInstance
{
    static TangramDefaultElementFactory *_elementFactory= nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _elementFactory = [[TangramDefaultElementFactory alloc] init];
    });
    return _elementFactory;
}
- (instancetype)init
{
    if (self = [super init]) {
        self.elementForbiddenPropertyArray = [[NSMutableArray alloc]init];
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([UIView class], &count);
        for (int i = 0; i < count; i++) {
            objc_property_t property = properties[i];
            // Get property name (C String)
            const char *cName = property_getName(property);
            // Transfer to objective-c string
            NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
            [self.elementForbiddenPropertyArray addObject:name];
        }
        NSArray *otherForbiddenArray = @[@"margin",@"display",@"colspan",@"aspectRatio",@"height",@"width",@"position"];
        [self.elementForbiddenPropertyArray addObjectsFromArray:otherForbiddenArray];

    }
    return self;
}




/**
 Return view by model
 
 @param model ItemModel Generated by ItemModelFactoty
 @return view
 */
+ (UIView *)elementByModel:(NSObject<TangramItemModelProtocol> *)model
{
    //if it's model for inner layout, we return nil. Here won't generate any UIView
    if ([model respondsToSelector:@selector(layoutIdentifierForLayoutModel)] && model.layoutIdentifierForLayoutModel && model.layoutIdentifierForLayoutModel.length > 0) {
        return nil;
    }
    NSObject *object = nil;
    NSString *elementClassName = model.linkElementName;
    if ([model isKindOfClass:[TangramDefaultItemModel class]] && [model respondsToSelector:@selector(linkElementName)] &&  model.linkElementName.length > 0) {
        object = [[NSClassFromString(elementClassName) alloc] init];
        if ([object isKindOfClass:[UIView class]]) {
            [self fillObjectPropertyByObject:(UIView *)object viewModel:(TangramDefaultItemModel *)model];
        }
    }
    return (UIView *)object;
}

/**
 Return view after be refreshed
 
 @param  element to be refreshed
 @return element after refreshed
 */
+ (UIView *)refreshElement:(UIView *)element byModel:(NSObject<TangramItemModelProtocol> *)model
{
    if (nil == element) {
        return nil;
    }
    if ([model isKindOfClass:[TangramDefaultItemModel class]] && [model respondsToSelector:@selector(linkElementName)] &&  model.linkElementName.length > 0) {
        [self fillObjectPropertyByObject:element viewModel:(TangramDefaultItemModel *)model];
    }
    return element;
}

+ (void)fillObjectPropertyByObject:(NSObject *)object viewModel:(TangramDefaultItemModel *)model
{
    TangramDefaultElementFactory *elementFactory = [TangramDefaultElementFactory sharedInstance];
    for (NSString *key in [model bizKeys]) {
        //首先，确保可以取出来值
        if ([self objectHasSetter:object propertyName:key]
            && ![elementFactory.elementForbiddenPropertyArray containsObject:key]
            && [model bizValueForKey:key] != nil  ) {
            //在这里判一下类型
            id bizValue = [model bizValueForKey:key];
            [self fillObjectPropertyByObject:object key:key value:bizValue];
        }
    }
    for (NSString *key in [model styleKeys]) {
        if ([self objectHasSetter:object propertyName:key]
            && ![elementFactory.elementForbiddenPropertyArray containsObject:key]
            && [model styleValueForKey:key] != nil) {
            id styleValue = [model styleValueForKey:key];
            [self fillObjectPropertyByObject:object key:key value:styleValue];
        }
    }
}
+ (void)fillObjectPropertyByObject:(NSObject *)object key:(NSString *)key value:(id)value
{
    //拿到Property
    objc_property_t propMeta = class_getProperty([object class], [key UTF8String]);
    if (propMeta != NULL) {
        NSString *attributesString = [NSString stringWithUTF8String:property_getAttributes(propMeta)];
        //支持property参数为 NSString/NSArray/NSDictionary/NSNumber 其他的类型直接跳过
        if ([attributesString containsString:@"NSString"]) {
            if (![value isKindOfClass:[NSString class]]) {
                return;
            }
            [object setValue:value forKey:key];
        } else if ([attributesString containsString:@"NSMutableString"]) {
            if (![value isKindOfClass:[NSString class]]) {
                return;
            }
            [object setValue:[NSMutableString stringWithString:value] forKey:key];
        } else if ([attributesString containsString:@"NSArray"]) {
            if (![value isKindOfClass:[NSArray class]]) {
                return;
            }
            [object setValue:value forKey:key];
        } else if ([attributesString containsString:@"NSMutableArray"]) {
            if (![value isKindOfClass:[NSArray class]]) {
                return;
            }
            [object setValue:[NSMutableArray arrayWithArray:value] forKey:key];
        } else if ([attributesString containsString:@"NSDictionary"]) {
            if (![value isKindOfClass:[NSDictionary class]]) {
                return;
            }
            [object setValue:value forKey:key];
        } else if ([attributesString containsString:@"NSMutableDictionary"]) {
            if (![value isKindOfClass:[NSDictionary class]]) {
                return;
            }
            [object setValue:[NSMutableDictionary dictionaryWithDictionary:value] forKey:key];
        }else if ([attributesString containsString:@"NSData"]) {
            if (![value isKindOfClass:[NSData class]]) {
                return;
            }
            [object setValue:[NSData dataWithData:value] forKey:key];
        }
        else if ([attributesString containsString:@"NSNumber"]) {
            if ([value isKindOfClass:[NSNumber class]]) {
                [object setValue:value forKey:key];
            }
            else if ([value isKindOfClass:[NSString class]]) {
                NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
                formatter.numberStyle = NSNumberFormatterDecimalStyle;
                NSNumber *number = [formatter numberFromString:value];
                [object setValue:number forKey:key];;
            }
        }
    }
    else{
        @try {
            [object setValue:value forKey:key];
        } @catch (NSException *exception) {
            NSLog(@"Error at Tangram find setter in element");
        } @finally {
            
        }
        
    }
}

+ (BOOL)objectHasSetter:(NSObject *)object propertyName:(NSString *)propertyName
{
    NSString *setterString = [NSString stringWithFormat:@"set%@%@:",
                              [[propertyName substringToIndex:1] capitalizedString],
                              [propertyName substringFromIndex:1]];
    return [object respondsToSelector:NSSelectorFromString(setterString)];
}

+ (BOOL)objectHasGetter:(NSObject *)object propertyName:(NSString *)propertyName
{
    return [object respondsToSelector:NSSelectorFromString(propertyName)];
}

@end
